#include <iostream>
#include <string>
#include <cstdio>
#include <sstream>

#include "pin.H"
#include "pin_trace.h"

using namespace std;
using namespace pintrace;

string gettypename(uint32_t id)
{
	
	switch (id) {
    case REGTYPE_LAST:  return string("REGTYPE_LAST");
    case MEMTYPE_LAST:  return string("MEMTYPE_LAST");
    case VT_NONE:  return string("VT_NONE");
    case VT_REG8:  return string("VT_REG8");
    case VT_REG16:  return string("VT_REG16");
    case VT_REG32:  return string("VT_REG32");
    case VT_REG64:  return string("VT_REG64");
    case VT_REG128:  return string("VT_REG128");
    case VT_MEM8:  return string("VT_MEM8");
    case VT_MEM16:  return string("VT_MEM16");
    case VT_MEM32:  return string("VT_MEM32");
    case VT_MEM64:  return string("VT_MEM64");
    case VT_MEM128:  return string("VT_MEM128");
    case VT_MEM256:  return string("VT_MEM256");
    default: return string("unknow");
	}
}

string getusename(uint32_t id)
{
	
	switch (id) {
    case 0x01:  return string("RD");
    case 0x10:  return string("WR");
    case 0x11:  return string("RW");
    default:  return string("NO");
    }
}

string getlocname(uint32_t id, uint32_t type)
{
    string ret = REG_StringShort(REG(id));
    if(ret[0] == '*')
    {
		//        ret.erase(0, 13);
        stringstream sstrm;
        sstrm << hex << id;
        sstrm.clear();
        ret = sstrm.str();
    }
    return ret;
}

int main(int argc, char **argv) {
	
	pintrace::TraceReader tr(argv[1]);
	
	printf("Frame count: %d\n\n", tr.count());
	printf("============================================================================\n");
	
	uint32_t last_addr=0;
	
	while(tr.pos() < tr.count()) {
		
		uint64_t current_pos=tr.pos();
		
		pintrace::Frame *f = tr.next();
		
		
		switch(f->type) {
		case FRM_STD:
			{
				pintrace::StdFrame *sf = (pintrace::StdFrame *) f;
				
				if( (unsigned char)(sf->rawbytes[0]) == 0xf3 &&  (unsigned char)(sf->rawbytes[1]) == 0xa5 && (sf->insn_length == 2))//rep movs
					for (uint32_t i = 0 ; i < sf->values_count ; i ++)
					{
						if((getlocname(sf->locs[i], sf->types[i])).compare("ecx")==0 && sf->taint[i])//ecx tainted
                                            if(sf->addr != last_addr)
                                            {
								last_addr = sf->addr;
								printf("Standard frame.\n");
								printf("Pos: %d\n", current_pos);
								printf("Addr: 0x%x\n", sf->addr);
								printf("TID: %d\n", sf->tid);
								printf("Insn length: %d\n", sf->insn_length);
								printf("Values count: %d\n", sf->values_count);
								printf("Insn bytes: ");
								
								unsigned int len =
									(sf->insn_length == 0) ? MAX_INSN_BYTES : sf->insn_length;
								
								for (unsigned int i = 0; i < len; i++) {
									printf("%x ",  (unsigned char)(sf->rawbytes[i]));
								}
								
								printf("\n     Val\t   Taint\t    Locs\t   Types\t  Usages\n");
								printf("\n--------------------------------------------------------------------------\n");
								for (uint32_t i = 0 ; i < sf->values_count ; i ++)
									printf("%8x\t%8x\t%8s\t%8s\t%8s\n", sf->values[i], sf->taint[i], getlocname(sf->locs[i], sf->types[i]).c_str(), gettypename(sf->types[i]).c_str(), getusename(sf->usages[i]).c_str());
								printf("============================================================================\n");
								break;
                                             }
					}
                    delete f;
					break;
			}
		case FRM_STD2:
			{
				pintrace::StdFrame2 *sf = (pintrace::StdFrame2 *) f;
				if( (unsigned char)(sf->rawbytes[0]) == 0xf3 &&  (unsigned char)(sf->rawbytes[1]) == 0xa5 && (sf->insn_length == 2))//rep movs
					for (uint32_t i = 0 ; i < sf->values_count ; i ++)
					{
						if((getlocname(sf->locs[i], sf->types[i])).compare("ecx")==0 && sf->taint[i])//ecx tainted
                                            if(sf->addr != last_addr)
                                            {
                                           // printf("LastAddr: 0x%x\n", last_addr);
								last_addr = sf->addr;
								printf("Standard frame (enhanced).\n");
								printf("Pos: %d\n", current_pos);
								printf("Addr: 0x%x\n", sf->addr);
								printf("TID: %d\n", sf->tid);
								printf("Insn length: %d\n", sf->insn_length);
								printf("Values count: %d\n", sf->values_count);
								
								printf("Insn bytes: ");
								
								unsigned int len =
									(sf->insn_length == 0) ? MAX_INSN_BYTES : sf->insn_length;
								
								for (unsigned int i = 0; i < len; i++) {
									printf("%x ", (unsigned char)(sf->rawbytes[i]));
									
								}
								
								
								printf("\n     Val\t   Taint\t    Locs\t   Types\t  Usages\n");
								printf("\n--------------------------------------------------------------------------\n");
								for (uint32_t i = 0 ; i < sf->values_count ; i ++)
									printf("%8x\t%8x\t%8s\t%8s\t%8s\n", sf->values[i].dword[0], sf->taint[i], getlocname(sf->locs[i], sf->types[i]).c_str(), gettypename(sf->types[i]).c_str(), getusename(sf->usages[i]).c_str());
								
								printf("============================================================================\n");
								delete f;
								break;
							}
					}
					delete f;
					break;
                }
			
		default:
			break;
		}
		
	}
	//   cerr << acc;
	return 0;
}

